﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.Net;
using DoubleH.Utility;
using Table = FCNS.Data.Table;
using System.Net.NetworkInformation;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;

namespace ItDbS
{
    /// <summary>
    /// SearchWindow.xaml 的交互逻辑
    /// </summary>
    public partial class SearchWindow : Window
    {
        [DllImport("Iphlpapi.dll")]
        private static extern int SendARP(Int32 dest, Int32 host, ref Int64 mac, ref Int32 length);
        [DllImport("Ws2_32.dll")]
        private static extern Int32 inet_addr(string ip);

        public SearchWindow()
        {
            InitializeComponent();

            InitVar();
            InitEvent();
        }

        System.Threading.Thread thread = null;
        ObservableCollection<TempClass> allHost = new ObservableCollection<TempClass>();
        NetworkInterface netInterface = null;

        private void InitVar()
        {
            checkListBoxHost.ItemsSource = allHost;

            foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (ni.OperationalStatus == OperationalStatus.Up)
                {
                    netInterface = ni;
                    break;
                }
            }
        }

        private void InitEvent()
        {
            buttonSearch.Click += (ss, ee) => Search();
            buttonAdd.Click += (ss, ee) => AddSearch();
            this.Closing += (ss, ee) => CloseSearch();
        }

        private void AddSearch()
        {
            foreach (object obj in checkListBoxHost.SelectedItems)
            {
                TempClass tc = obj as TempClass;
                Table.ItDbS db = new Table.ItDbS() { Flag = Table.ItDbS.EnumFlag.硬件 };
                db.Name = tc.Name;
                db.IpV4 = tc.IpV4;
                db.IpV6 = tc.IpV6;
                db.Mac = tc.Mac;
                db.Enable = Table.ItDbS.EnumEnable.激活;
                Table.DataTableS.EnumDatabaseStatus result = db.Insert();
                if (result != Table.DataTableS.EnumDatabaseStatus.操作成功)
                    MessageWindow.Show(tc.Name + " " + tc.IpV4 + " 添加失败");
            }
        }

        private void CloseSearch()
        {
            if (thread != null)
            {
                thread.Abort();
                thread = null;
            }
            this.Dispatcher.Invoke(new Action(() => buttonSearch.Content = "搜索"));
        }

        private void Search()
        {
            if (thread != null)
            {
                CloseSearch();
                return;
            }
            allHost.Clear();


            if (netInterface == null)
            {
                MessageWindow.Show("网卡参数读取失败");
                return;
            }

            IPAddress ip = null;
            foreach (UnicastIPAddressInformation info in netInterface.GetIPProperties().UnicastAddresses)
            {
                if (info.Address.ToString().Length < 16)
                {
                    ip = DoubleH.Utility.Net.NetUtility.GetBroadcast(info.Address.ToString(), info.IPv4Mask.ToString());
                    break;
                }
            }
            if (ip == null)
                return;

            buttonSearch.Content = "停止";
            progressBar1.Value = 0;
            thread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(SearchHost));
            thread.Start(ip);
        }

        private void SearchHost(object obj)
        {
            IPAddress ip = obj as IPAddress;
            string[] str = ip.ToString().Split('.');
            int maxIP = int.Parse(str[3]);
            string ips = str[0] + "." + str[1] + "." + str[2] + ".";
            string ipe = str[0] + "." + str[1] + "." + str[2] + "." + (maxIP - 1).ToString();
            this.Dispatcher.Invoke(new Action<string, int>(UpdateLabelIP), ips + "1/" + ipe, maxIP);
            Ping ping = new Ping();
            int timeOut = (int)this.Dispatcher.Invoke(new Func<int>(() => { return integerUpDownTimeOut.Value.Value; }));

            for (int i = 1; i < maxIP; i++)
            {
                this.Dispatcher.Invoke(new Action<string>(UpdateLabelIpNow), ips + i);
                TempClass tc = null;
                try
                {
                    if (ping.Send(ips + i, timeOut).Status != IPStatus.Success)
                        continue;

                    tc = new TempClass();
                    tc.IpV4 = ips + i;
                    IPHostEntry entry = Dns.GetHostEntry(ips + i);
                    foreach (IPAddress ia in entry.AddressList)
                    {
                        if (ia.ToString().Length > 16)
                            tc.IpV6 = entry.AddressList[0].ToString();
                    }
                    tc.Mac = GetRemoteMac(ip.ToString(), tc.IpV4);
                    tc.Name = entry.HostName;
                }
                catch { }
                finally
                {
                    if (tc != null)//有可能读取到IP地址,但无法获取名称.这种情况也是应该添加到列表的.
                        this.Dispatcher.Invoke(new Action(() => allHost.Add(tc)));

                    this.Dispatcher.Invoke(new Action(UpdateProcess));
                }
            }
            ping.Dispose();
            this.Dispatcher.Invoke(new Action<string>(UpdateLabelIpNow), string.Empty);
            CloseSearch();
        }

        private string GetRemoteMac(string localIP, string remoteIP)
        {
            Int32 ldest = inet_addr(remoteIP); //目的ip
            Int32 lhost = inet_addr(localIP); //本地ip

            try
            {
                Int64 macinfo = new Int64();
                Int32 len = 6;
                int res = SendARP(ldest, 0, ref macinfo, ref len);
                return Convert.ToString(macinfo, 16);
            }
            catch
            {
            }
            return string.Empty;
        }

        private void UpdateLabelIpNow(string text)
        {
            labelIpNow.Content = text;
        }

        private void UpdateProcess()
        {
            progressBar1.Value += 1;
        }

        private void UpdateLabelIP(string text, int maxIp)
        {
            progressBar1.Maximum = maxIp;
            labelIp.Content = text;
        }
    }

    public class TempClass
    {
        public string Name { get; set; }
        public string IpV4 { get; set; }
        public string IpV6 { get; set; }
        public string Mac { get; set; }
        public override string ToString()
        {
            return IpV4 + "   " + Name + "   " + Mac;
        }
    }
}